import json
import socket
import time
from threading import Thread, Lock
from queue import Queue

task = Queue() # 模拟Redis的订阅与发布
clients = {}  # 保存是所有用户ID和对应的客户端连接的线程
lock = Lock()


class ClientThread(Thread):
    def __init__(self, client):
        super(ClientThread, self).__init__(name='Client')
        self.client = client  # socket连接客户端对象
        self.start()

    def run(self) -> None:

        while True:
            try:
                # 获取客户端发送过来的消息
                msg = self.client.recv(1024 * 8)  # bytes
                msg_str = msg.decode('utf-8')
                # msg_str =>  user_id=1001
                if msg_str.startswith('user_id'):
                    self.user_ident = msg_str.split('=')[-1]
                    print(self.user_ident, '用户已连接')
                    # 是否加锁
                    with lock:
                        clients[self.user_ident] = self
                elif msg_str == 'bye':
                    # 关闭连接
                    with lock:
                        del clients[self.user_ident]
                    break
            except:
                pass

        self.client.close()  # 释放资源

    def send_msg(self, msg):
        self.client.send(msg.encode('utf-8'))
        print(msg, '消息已发送', self.user_ident)

class ConnectThread(Thread):
    def __init__(self, server):
        super(ConnectThread, self).__init__(name='Connect')
        self.server = server
    def run(self) -> None:
        print('---推送服务已启动--')
        while True:
            client, address = self.server.accept()  # 开始接收客户端连接
            print(address, '----已连接，等待验证---')
            # 由线程托管
            ClientThread(client)

class MsgSubjectThread(Thread):
    def run(self) -> None:
        while True:
            msg = task.get()
            # 分解消息
            ids, title, url = msg.split()
            msg_body = json.dumps({
                'title': title,
                'url': url
            })
            for uid in ids.split(','):
                client: ClientThread = clients.get(uid, None)
                # 判断用户是否在线
                if client:
                    client.send_msg(msg_body)


# 创建socket对象， 实现网络间不同终端连接
server = socket.socket(socket.AF_INET)
server.bind(('0.0.0.0', 7600))  # 绑定网络服务
server.listen()
conn_thread = ConnectThread(server)  # 获取所有客户端的连接
conn_thread.start()
time.sleep(3)

MsgSubjectThread().start()

while True:
    # 主线程
    msg = input('输入消息')
    # 指定用户，发送相关的消息
    # msg => 1001,1002,1003 万万聊三国已更新 http://live.play/sanguo/p12/
    task.put(msg)
    time.sleep(2)








